home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / FBSpriteWorld 1.05b / Project 1.05b / SWSpinningGlobe.11.main < prev    next >
Encoding:
Text File  |  1994-05-10  |  17.0 KB  |  517 lines  |  [TEXT/ZBAS]

  1. '
  2. '       FBSpinningGlobe.main by Robert Hommel
  3. '       © Copyright 1994
  4. '       All rights granted for any use whatsoever
  5. '
  6. '       ------------------------------------------------------------
  7. '       Additional Modifications by: Andrew Gariepy
  8. '
  9. '       Works with 32 bit quickdraw only                    04/26/94
  10. '       Added dialog & menu event handling for BG running
  11. '       Reduced memory requirements by 1/3                  04/28/94
  12. '       Fixed Power Mac problems 
  13. '       Fixed unlocked GWorld bugs                          04/29/94
  14. '       Fixed numerous other things for speed & reliability
  15. '
  16. '       Testing for reliability was performed on a Mac IIfx, Q-700, Q-610,
  17. '       and 840av, plus Power Macs 6100/60, 7100/66av, and 8100/80. All
  18. '       tests were run under System 7.1 and 7.12.
  19. '
  20. '       The best speed we saw was the 8100 which achieved a frame rate
  21. '       of 65 frames/sec (fps) at millions of colors. 256 colors peaked
  22. '       the rate at about 80 fps. The 6100 could reach 65 fps when run 
  23. '       at 4 color mode. Remember though, this was under the emulator
  24. '       which required thousands of mode switches per second of animation.
  25. '       Not a bad speed considering.
  26. '
  27. '       ------------------------------------------------------------
  28. '
  29. '       This example program builds on the foundation of SWSimpleTest to
  30. '       create a more complex animation.  It demonstrates the use of Sprites
  31. '       with multiple Frames, the use of multiple Layers to produce a
  32. '       three-dimensional appearance, and inactive (non-mobile) Sprites.
  33. '
  34. '       You will notice a slight slowing of the animation as the Globe
  35. '       Sprites pass in front of or behind the SpriteWorld Text Sprite.
  36. '       FBSpriteWorld does rigorous checking to make sure that only those
  37. '       Sprites that have moved or changed frames are drawn.  Most of the
  38. '       time, the Text Sprite does not need to be drawn; however, whenever
  39. '       a Globe intersects the Text, FBSpriteWorld must render at least a
  40. '       part of the Text Sprite, and this causes the animation to slow down.
  41. '       This slowing is only noticeable because most of the Globe Sprites
  42. '       are moved 'as quickly as possible.'  If this were anything other
  43. '       than a demo, we would assign move times to each Globe Sprite suf-
  44. '       ficient to keep them moving at a steady pace.
  45. '
  46. '       We can learn several lessons from the 'slowing' phenomenon: namely,
  47. '       keep the number of Sprites to a minimum, keep the number of moving
  48. '       Sprites as small as possible, avoid intersecting inactive Sprites,
  49. '       and for optimum performance, keep the Sprites small.  If you must
  50. '       have large Sprites, try to make them wide rather than tall.
  51. '
  52. '       When you click the mouse button to exit this program, an Alert will
  53. '       display showing the number of animation frames performed per second.
  54. '       On my original Mac LC, I get about 14.5 frames per second.  The 
  55. '       C version of SpriteWorld by Tony Myles clocks a cool 22 frames per
  56. '       second using CopyBits, and 30+ with an assembly bit blitter!  Such
  57. '       figures indicate we've got a long way to go with improving the 
  58. '       animation engine - any ideas out there?
  59. '
  60. '       Disclaimer:  I've tested these routines quite thoroughly on my Mac
  61. '       LC running System 7.01 and FB 1.02c.
  62. '       I make no promises or warranties of any kind.
  63. '
  64. '*********************************************************************
  65. '
  66. 'TRON b
  67. COMPILE 0, _MacsBugLabels _caseInsensitive
  68. RESOURCES "FBSpriteWorld.RSRC","APPLFbSw"
  69. '
  70. '---------------------------- GLOBALS --------------------------------
  71. '
  72. GLOBALS "FBSpriteWorld.glbl"
  73. '
  74. _backPatRSRC     = 128
  75. _spriteGlobeRSRC = 132
  76. _spriteTextRSRC  = 228
  77. '
  78. _SpriteWnd = 1
  79. _StatusWnd = 2
  80. '
  81. END GLOBALS
  82. '
  83. DIM T,L,B,R
  84. DIM T1,L1,B1,R1
  85. DIM curRect.8
  86. DIM mySW.SpriteWorldRec
  87. DIM myLayer.SWLayerRec(1)
  88. DIM textLayer.SWLayerRec
  89. DIM mySprite.SWSpriteRec(3)
  90. DIM textSprite.SWSpriteRec
  91. DIM myFrame.SWFrameRec(9)
  92. DIM textFrame.SWFrameRec
  93. DIM wndPort&               
  94. '
  95. WINDOW OFF
  96. GOTO "Main"
  97. '
  98. '--------------------------- INCLUDES --------------------------------
  99. '
  100. INCLUDE "FBSpriteWorld.incl"
  101. '
  102. '------------------------- ERROR HANDLER -----------------------------
  103. '                       DestRect        Rect to Center
  104. '       On Exit         DestRect        Centered in SourceRect
  105. '
  106. LOCAL
  107. DIM ST,SL,SB,SR
  108. DIM DT,DL,DB,DR
  109. LOCAL FN CenterRects(SourceRect&,DestRect&)
  110.    ST;8=SourceRect&                               '••• Get Rect's •••
  111.    DT;8=DestRect&
  112.    DeltaVert=ST+((SB-ST)-(DB-DT))/2-DT            '
  113.    DeltaHorz=SL+((SR-SL)-(DR-DL))/2-DL
  114.    DT=DT+DeltaVert
  115.    DL=DL+DeltaHorz
  116.    DB=DB+DeltaVert
  117.    DR=DR+DeltaHorz
  118.    BLOCKMOVE @DT,DestRect&,8                      '••• RETURN DEST RECT •••
  119. END FN
  120. '
  121. '               FUNTION TO PRINT WHOLE WINDOW CONTENTS
  122. '
  123. LOCAL MODE
  124. DIM T,L,B,R
  125. DIM PT,PL,PB,PR
  126. LOCAL FN PrintWindow(SWPtr&)
  127.    DEF LPRINT
  128.    LONG IF PRCANCEL=0                             '••• Not Canceled? •••
  129.       CALL GETGWORLD(CurrPort&,CurrDev&)
  130.       CALL SETGWORLD(SWPtr&.loadFramePtr&,0)
  131.       T;8 = SWPtr&+_boundsRect
  132.       Pict& = USR GETPICT(T)                      'take snapshot of background
  133.       CALL SETGWORLD(CurrPort&,CurrDev&)
  134.       LONG IF Pict&
  135.          ROUTE 128
  136.          PT=0 : PL=0 : PB=WINDOW(7) : PR=WINDOW(6)'Page Rectangle
  137.          FN CenterRects(@PT,@T)                   '••• CENTER ON PAPER •••
  138.          PICTURE (L,T),Pict&                      '••• SEND PICT TO PRINTER •••
  139.          KILL PICTURE Pict&                       '••• DISPOSE OF PICTURE •••
  140.          CALL PENNORMAL
  141.          CALL FRAMERECT(T)
  142.       END IF
  143.    XELSE
  144.       BEEP
  145.    END IF
  146.    CLOSE LPRINT
  147. END FN
  148. '
  149. '
  150. '
  151. CLEAR LOCAL
  152. LOCAL FN FatalError(errCode)
  153.    '
  154.    '     Simple error handler.  You'll want to improve on this in your
  155.    '     program...
  156.    '
  157.    LONG IF errCode<>_noErr
  158.       SELECT errCode
  159.          CASE _swTooManyLayers     : errStr$="Out of Memory."
  160.          CASE _swTooManySprites    : errStr$="Too many Sprites."
  161.          CASE _swTooManyFrames     : errStr$="Too many Frames."
  162.          CASE _swNotSystemSeven    : errStr$="SpriteWorld requires System 7!"
  163.          CASE _swTimeMgrNotPresent : errStr$="SpriteWorld requires Time Manager."
  164.          CASE _swOutOfMemory       : errStr$="Out of Memory."
  165.          CASE ELSE                 : errStr$="Unknown error."
  166.       END SELECT
  167.       
  168.       tmp$="Error Code:"+STR$(errCode)
  169.       CALL PARAMTEXT(errStr$,tmp$,"","")
  170.       x=FN STOPALERT(1,0)
  171.       END
  172.    END IF
  173. END FN
  174. '
  175. '
  176. '
  177. CLEAR LOCAL MODE
  178. LOCAL FN GetBestMonitor(@T&,TopHeight)
  179.    gdHndl& = FN GETDEVICELIST                     'get first device in list
  180.    MenuBar = {_Mbarheight}                        'If Main Monitor
  181.    DO                                             'loop thu monitor list
  182.       Depth = {[gdHndl&..gdPMap&]+_pmPixelSize}   'Current Depth
  183.       LONG IF Depth > BestDepth
  184.          BestDepth  = Depth
  185.          BLOCKMOVE [gdHndl&]+_gdRect,T&,8         'send back the rect
  186.          T&.Top% = T&.Top% + MenuBar + TopHeight
  187.       END IF
  188.       MenuBar = 0                                 'Not Main Monitor
  189.       gdHndl& = FN GETNEXTDEVICE(gdHndl&)
  190.    UNTIL gdHndl& = 0                              'till found or no more devices
  191. END FN = BestDepth
  192. '
  193. '------------------------ SPRITEWORLD PROCS --------------------------
  194. '
  195. "SWBounceMoveProc"
  196. ENTERPROC(SWPtr&,spritePtr&,curRectPtr&)
  197.    '
  198.    '     standard bounce movement proc.  Keeps sprite inside sprite boundsRect
  199.    '
  200.    dx = spritePtr&.xDelta% 
  201.    dy = spritePtr&.yDelta%
  202.    LONG IF curRectPtr&.left%+dx          <= spritePtr&.sBoundsRect.left%
  203.       spritePtr&.xDelta%   = -dx 
  204.    XELSE
  205.       LONG IF curRectPtr&.right%+dx       >= spritePtr&.sBoundsRect.right%
  206.          spritePtr&.xDelta% = -dx 
  207.       END IF
  208.    END IF
  209.    LONG IF curRectPtr&.top%+dy           <= spritePtr&.sBoundsRect.top%
  210.       spritePtr&.yDelta%   = -dy 
  211.    XELSE
  212.       LONG IF curRectPtr&.bottom%+dy      >= spritePtr&.sBoundsRect.bottom%
  213.          spritePtr&.yDelta% = -dy
  214.       END IF
  215.    END IF
  216. EXITPROC
  217. RETURN
  218. '
  219. '       Sets the frameTTHasFired or moveTTHasFired field of the sprite record
  220. '       to _zTrue (-1).  Called by the Time Manager if frameTimeInterval or
  221. '       moveTimeInterval field of sprite record > 0.
  222. '
  223. "SWTimeTask"
  224. `                 move.w      #-1,tmXQSize(a1)  ;[move|frame]TTHasFired=_zTrue
  225. `                 rts                           ;return
  226. '
  227. '
  228.  
  229.  
  230. '-------------------------- MAIN LOOP --------------------------------
  231. '
  232. "Main"
  233.  
  234. CURSOR _watchCursor                               'takes a few seconds to set up
  235. OrigMem& = SYSTEM(_Memavail)
  236. '
  237. '--------------------------------------------------------------------
  238. 'Initialization and Set Up
  239. '--------------------------------------------------------------------
  240. '
  241. err = FN SWEnterSpriteWorld                       'Can we run in this environment?
  242. FN FatalError(err)
  243. SWOpened = _ZTrue
  244. '
  245. '
  246. '
  247.  
  248. '
  249. '       Open a window and draw pretty background
  250. '
  251. FN GetBestMonitor(T1,20)                          'Find Best Screen
  252. '
  253. pict& = FN GETPICTURE(128)                        'BackGround Picture
  254. CALL DETACHRESOURCE(pict&)
  255. T;8 = [pict&]+2 : CALL OFFSETRECT(T,-L,-T)        'Size of Picture
  256. FN CenterRect(T,T1)                               'Center on Best Monitor
  257. WINDOW #_SpriteWnd,"Spinning Globe",(L,T)-(R,B),_Docnogrow_Nogoaway_Updatevisrgn'open a window the same size as PICT
  258. COORDINATE WINDOW
  259. CALL OFFSETRECT(T,-L,-T)                          'Remove Offset
  260. PRINT %(R/2-60,B/2);"Building Sprite Worlds";
  261. '
  262. wndPort& = WINDOW(_WndPointer)                    'get grafPtr
  263. '
  264. '// NOTE:  At this point, it would be easier to create the      //
  265. '// SpriteWorld based on the window port by using               //
  266. '// SWCreateSWFromWindow, as we have in the other examples.     //
  267. '// However, here we'll create the SpriteWorld from 'scratch'   //
  268. '// with our own background PICT and bounding rectangle.  This  //
  269. '// is the technique you would use to create a SpriteWorld with //
  270. '// a bounding rectangle smaller than the window's PortRect, or //
  271. '// to use a background different than the current background   //
  272. '// of the window.                                              //
  273. '
  274. '
  275. '       Create SpriteWorld
  276. '
  277.  
  278. err = FN SWCreateSpriteWorld(@mySW,wndPort&,wndPort&+_portRect,pict&)
  279. FN FatalError(err)
  280. '
  281. '       get time task ptr (same for all sprites)
  282. '
  283. ttPtr& = LINE "SWTimeTask"
  284. '
  285. '--------------------------------------------------------------------
  286. '       Create Globe Sprites
  287. '--------------------------------------------------------------------
  288. '
  289. '       get moveProc ptr (same for all sprites)
  290. '
  291. movePtr& = LINE "SWBounceMoveProc"
  292. '
  293. '       create first globe sprite
  294. '
  295. err=FN SWSpriteFromPict(@mySprite(0),0,0,0,wndPort&+_portRect,_zTrue,2,2,-1,ttPtr&,movePtr&,_spriteGlobeRSRC)
  296. FN FatalError(err)
  297. '
  298. '       add frames to globe sprite (add frames before clonning!)
  299. '
  300. FOR x = 0 TO 9
  301.    err = FN SWFrameFromPict(@myFrame(x),_spriteGlobeRSRC+(x*3))
  302.    FN FatalError(err)
  303.    err = FN SWAddFrameToSprite(@mySprite(0),@myFrame(x))
  304.    FN FatalError(err)
  305. NEXT
  306. '
  307. '       clone sprite(0) to make sprites 1-3
  308. '
  309. FOR x = 1 TO 3
  310.    FN SWCloneSprite(@mySprite(0),@mySprite(x),ttPtr&)
  311. NEXT
  312. '
  313. '       set sprite locations for sprites 1-3
  314. '
  315. FN SWSetSpriteLocation(@mySprite(1),R-60,0)
  316. FN SWSetSpriteLocation(@mySprite(2),R-60,B-60)
  317. FN SWSetSpriteLocation(@mySprite(3),0,B-60)
  318. '
  319. '       change sprite frame advance for sprites 1 and 3
  320. '
  321. FN SWSetSpriteFrameAdv(@mySprite(1),1)
  322. FN SWSetSpriteFrameAdv(@mySprite(3),1)
  323. '
  324. '       change sprite move delta for sprites 0 and 2
  325. '
  326. FN SWSetMoveDelta(@mySprite(0),1,1)
  327. FN SWSetMoveDelta(@mySprite(2),6,6)
  328. '
  329. '       set sprite move time for sprite 0 (all others will move as fast as they can)
  330. '
  331. FN SWSetMoveTime(@mySprite(0),200)
  332. '
  333. '       set sprite frame time for sprite 1 (all others will advance frames as fast as they can)
  334. '
  335. FN SWSetFrameTime(@mySprite(1),100)
  336. '
  337. '--------------------------------------------------------------------
  338. '       Create Text Sprite
  339. '--------------------------------------------------------------------
  340. '
  341. '// NOTE:  Normally, we use SWSpriteFromPict to create a sprite   //
  342. '// that is based on a PICT resource, like our text sprite.  For  //
  343. '// purposes of demonstration, we'll create this sprite from      //
  344. '// 'scratch,' by calling SWInitSprite instead.  We'll extract    //
  345. '// frameRect from the PICT resource, move it where we want it,   //
  346. '// then pass it to the initialization routine.  SWInitSprite     //
  347. '// would be most useful if you were making a sprite from some-   //
  348. '// thing other than a PICT resource, such as an object drawn on  //
  349. '// the screen.                                                       // 
  350. '
  351. '       create frame first so we can easily get its rect
  352. '
  353. err=FN SWFrameFromPict(@textFrame,_spriteTextRSRC)
  354. FN FatalError(err)
  355. '
  356. '       get frame rect
  357. '
  358. BLOCKMOVE @textFrame+_fBoundsRect,@curRect,8
  359. '
  360. '       center it in window rect
  361. '
  362. FN CenterRect(curRect,T)
  363. '
  364. '       create text sprite
  365. '
  366. FN SWInitSprite(@textSprite,0,@curRect,@T,_zTrue,0,0,0,ttPtr&,movePtr&)
  367. '
  368. '       set move and frame times to -1 (no frame advance or movement)
  369. '
  370. FN SWSetMoveTime (@textSprite,-1)
  371. FN SWSetFrameTime(@textSprite,-1)
  372. '
  373. '       add frame to text sprite
  374. '
  375. err=FN SWAddFrameToSprite(@textSprite,@textFrame)
  376. FN FatalError(err)
  377. '
  378. '---------------------------------------------------------------------
  379. '       Assemble the Pieces
  380. '---------------------------------------------------------------------
  381. '
  382. '       add globe sprites to globe layer 0
  383. '
  384. err=FN SWAddSpriteToLayer(@myLayer(0),@mySprite(0))
  385. FN FatalError(err)
  386. '
  387. err=FN SWAddSpriteToLayer(@myLayer(0),@mySprite(1))
  388. FN FatalError(err)
  389. '
  390. '       add text sprite to text layer 
  391. '
  392. err=FN SWAddSpriteToLayer(@textLayer,@textSprite)
  393. FN FatalError(err)
  394. '
  395. '       add globe sprites to globe layer 1
  396. '
  397. err=FN SWAddSpriteToLayer(@myLayer(1),@mySprite(2))
  398. FN FatalError(err)
  399. '
  400. err=FN SWAddSpriteToLayer(@myLayer(1),@mySprite(3))
  401. FN FatalError(err)
  402. '
  403. '       add layers to world
  404. '
  405. err=FN SWAddLayerToWorld(@mySW,@myLayer(0))
  406. FN FatalError(err)
  407. '
  408. err=FN SWAddLayerToWorld(@mySW,@textLayer)
  409. FN FatalError(err)
  410. '
  411. err=FN SWAddLayerToWorld(@mySW,@myLayer(1))
  412. FN FatalError(err)
  413. '
  414. '---------------------------------------------------------------------
  415. '       Final Set Up
  416. '---------------------------------------------------------------------
  417. '
  418. '       Prepare loadframe for animation
  419. '
  420. FN SWRefreshBackground(@mySW)
  421. '
  422. CURSOR _arrowCursor                               'we're ready to go...
  423. '
  424. '       Render 1st frame of animation
  425. '
  426. FN SWAnimateSpriteWorld(@mySW)
  427. '
  428. '---------------------------------------------------------------------
  429. '       Animation Loop
  430. '---------------------------------------------------------------------
  431. '
  432. WINDOW #_StatusWnd,"Status Window",(2,40)-(230,100),_Docround_Nogoaway
  433. TEXT 4,9,0,0
  434. '
  435. ON DIALOG   GOSUB "DIALOG"
  436. ON STOP     GOSUB "STOP"
  437. ON TIMER(2) GOSUB "TIMER"
  438. ON MENU     GOSUB "MENU"
  439. '
  440. a& = FN TICKCOUNT : frames&=0                     'set initial timer vars
  441. LastTime&  = FN TICKCOUNT
  442. '
  443. DO
  444.    HANDLEEVENTS                                   'be kind to system
  445.    FN SWProcessSpriteWorld(@mySW)                 'move sprites
  446.    FN SWAnimateSpriteWorld(@mySW)                 'render sprites
  447.    INC(frames&)                                   'keep track of animation frames
  448. UNTIL WndClosed
  449. END
  450. '
  451. '---------------------------------------------------------------------
  452. 'Dispose SpriteWorld and Exit
  453. '---------------------------------------------------------------------
  454. '
  455. "STOP"
  456. LONG IF SWOpened
  457.    SWOpened = _False
  458.    FN FatalError(FN SWDisposSpriteWorld(@mySW))
  459. END IF
  460. END
  461. '
  462. "DIALOG"
  463. D0 = DIALOG(0) : DN = DIALOG(D0)
  464. SELECT CASE D0
  465.    CASE _Wndrefresh
  466.       SELECT CASE DN
  467.          CASE _SpriteWnd : FN SWUpdateSpriteWorld(@mySW)
  468.          CASE _StatusWnd : GOSUB "TIMER"
  469.       END SELECT
  470.    CASE _Wndclose
  471.       WndClosed = _Ztrue
  472.    CASE _Wndclick
  473.       IF DN THEN WINDOW DN
  474. END SELECT
  475. RETURN
  476. '
  477. '
  478. '
  479. "MENU"
  480. M0 = MENU(0)
  481. M1=MENU(1)
  482. SELECT CASE M0
  483.    CASE 127 : X = FN ALERT(128,0)                 '••• APPLE MENU •••
  484.    CASE 1                                         '••• FILE MENU •••
  485.       SELECT CASE M1
  486.          CASE 1 : DEF PAGE                        'Page Layout
  487.          CASE 2                                   'Print
  488.             WINDOW OUTPUT _SpriteWnd
  489.             FN PrintWindow(@mySW)
  490.          CASE 4 : WndClosed = _Ztrue              'QUIT
  491.       END SELECT
  492.    CASE 2 : BEEP                                  '••• EDIT MENU •••
  493. END SELECT
  494. MENU
  495. RETURN
  496. '
  497. '
  498. '
  499. "TIMER"
  500. WINDOW OUTPUT _StatusWnd
  501. PrevTime&    = FN TICKCOUNT - LastTime&
  502. elapsedTime& = FN TICKCOUNT - a&
  503. CurrMem&     = SYSTEM(_Memavail)
  504. PRINT @(0,0); USING "#,###,###";frames& ;" frames drawn in ";
  505. LONG IF elapsedTime& < 60000
  506.    PRINT USING "###.#";elapsedTime&/60.  ;" Sec."'Less Than 1000 seconds...
  507. XELSE
  508.    PRINT USING "#,###";elapsedTime&/3600.;" Min."'More Than 1000 seconds...
  509. END IF
  510. PRINT "  Average Frames: ";USING "###.##";frames&\(elapsedTime&\60.)            ;" per second."
  511. PRINT "  Current Frames: ";USING "###.##";(frames&-LastCount&)\(PrevTime&\60.)  ;" per second."
  512. PRINT "     Memory Used: ";USING "##,###,###";OrigMem& - CurrMem&               ;" Bytes."
  513. PRINT "    Memory Avail: ";USING "##,###,###";CurrMem&                          ;" Bytes.";
  514. LastTime&  = FN TICKCOUNT
  515. LastCount& = frames&
  516. RETURN
  517.